﻿using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public struct ShadowState
{
    public uint m_TickCount;
    public Vector3 m_Pos;
    public Quaternion m_Rot;
}

public class Player : MonoBehaviour
{
    uint m_UserID;
    const string MOUSE_X = "Mouse X";
    const string MOUSE_Y = "Mouse Y";
    const string HORIZONTAL = "Horizontal";
    const string VERTICAL = "Vertical";
    [SerializeField] Vector3 m_CamOffset = new Vector3(0, 2.31f, -4.98f);
    float m_MoveSpeed = 3;
    bool m_StartUpdatePos;
    [SerializeField] float m_RotSensitive = 0.1f;
    [SerializeField] Text m_NameText;
    public string NickName { private set; get; }
    const int SERVER_MS_PER_TICK = 33;

    Camera m_Cam;
    Camera Cam
    {
        get
        {
            if (m_Cam == null)
            {
                m_Cam = Camera.main;
            }
            return m_Cam;
        }
    }

    public Vector3 TargetPos
    {
        get
        {
            return m_ShadowState.m_Pos;
        }
    }

    public uint PlayerID { private set; get; }
    Transform m_CacheTrans;
    public Transform CacheTrans
    {
        get
        {
            if (m_CacheTrans == null)
            {
                m_CacheTrans = this.transform;
            }
            return m_CacheTrans;
        }
    }

    Transform m_CamTrans;
    public Transform CamTrans
    {
        get
        {
            if (m_CamTrans == null)
            {
                m_CamTrans = Cam.transform;
            }
            return m_CamTrans;
        }
    }

    public ShadowState m_ShadowState;

    public bool IsAI()
    {
        return m_UserID == 0;
    }

    public void Init(uint userId, uint playerId, string nickName, ShadowState state)
    {
        m_UserID = userId;
        PlayerID = playerId;
        name = playerId.ToString();
        m_NameText.text = nickName;
        NickName = nickName;

        CacheTrans.position = state.m_Pos;
        CacheTrans.rotation = state.m_Rot;
        m_ShadowState = state;
        //LogManager.Error("tickcoun=" + state.m_TickCount);
    }

    public void UpdatePos(ShadowState state)
    {
        if (state.m_TickCount <= m_ShadowState.m_TickCount)
        {
            return;
        }
        var gap = 1.0f;
        if (state.m_TickCount > 0)
        {
            gap = (float)(state.m_TickCount - m_ShadowState.m_TickCount);
        }

        m_MoveSpeed = Vector3.Distance(state.m_Pos, CacheTrans.position) / (gap * (float)SERVER_MS_PER_TICK / 1000f);
        // Debug.LogError("playeId=" + PlayerID + ", pos=" + pos);
        m_StartUpdatePos = true;
        //LogManager.Error("prev tickcoun=" + m_ShadowState.m_TickCount + ", " + "new tickcoun=" + state.m_TickCount + ", speed=" + m_MoveSpeed);
        m_ShadowState = state;
    }

    public bool IsLocalPlayer()
    {
        if (Client.Instance == null)
        {
            return true; 
        }
        return Client.Instance.m_PlayerID == PlayerID;
    }

    Quaternion m_AimRotation;
    public void Tick()
    {
        if (!IsLocalPlayer())
        {
            if (m_StartUpdatePos)
            {
                SimWalk(TargetPos - CacheTrans.position);
            }
            return;
        }

        float h = Input.GetAxis(HORIZONTAL);
        float v = Input.GetAxis(VERTICAL);

#if !UNITY_EDITOR && !UNITY_WINDOWS
        v = Launcher.Instance.m_MoveLeft.m_Delta.y;
        h = Launcher.Instance.m_MoveLeft.m_Delta.x;
#endif

        if (v != 0 || h != 0)
        {
            // 获取camera相机的横向和前向
            var dir = Vector3ZeroY(CamTrans.right).normalized * h + Vector3ZeroY(CamTrans.forward).normalized * v;
            SimWalk(dir);
        }

        float mx = Input.GetAxis(MOUSE_X);
        float my = Input.GetAxis(MOUSE_Y);

#if !UNITY_EDITOR && !UNITY_WINDOWS
        my = Launcher.Instance.m_MoveRight.m_Delta.y * m_RotSensitive;
        mx = Launcher.Instance.m_MoveRight.m_Delta.x * m_RotSensitive;
#endif

        // my是饶X轴旋转的量，往上是逆时针，所以取负
        Vector3 deltaEulerAngles = new Vector3(-my, mx, 0) * 5f;
        var eulerAngle = m_AimRotation.eulerAngles;
        eulerAngle += deltaEulerAngles;
        if (eulerAngle.x > 180)
        {
            eulerAngle.x -= 360.0f;
        }
        if (eulerAngle.x < -20)
        {
            eulerAngle.x = -20;
        }
        else if (eulerAngle.x > 80)
        {
            eulerAngle.x = 80;
        }
        m_AimRotation.eulerAngles = eulerAngle;
        CamTrans.rotation = m_AimRotation;
        CamTrans.position = CacheTrans.position + m_CamOffset.y * Vector3.up + m_AimRotation * Vector3.forward * m_CamOffset.z;
    }

    void SimWalk(Vector3 dir)
    {
        if (dir.sqrMagnitude < 0.001f)
        {
            //dir = Vector3.one * 0.1f / (1 * (float)SERVER_MS_PER_TICK / 1000f);
            //dir = CacheTrans.forward;
            return;
        }
        else if (dir.sqrMagnitude < m_MoveSpeed * Time.deltaTime / 10f)
        {
            // for test
            dir = CacheTrans.forward; 

            //if (!IsLocalPlayer() && m_StartUpdatePos)
            //{
            //    //CacheTrans.position = TargetPos;
            //    if (!IsAI())
            //    {
            //        //CacheTrans.rotation = m_ShadowState.m_Rot;
            //    }
            //}
            //return;
        }

        CacheTrans.position += dir.normalized * m_MoveSpeed * Time.deltaTime;
        float angle = Vector3.Angle(CacheTrans.forward, dir);
        // Unity中eulerAngle顺时针为正
        // Cross是左手定则，因为Unity是左手坐标系
        var sign = Mathf.Sign(Vector3.Cross(CacheTrans.forward, dir).y);
        var dt = 360 * Time.deltaTime;
        if (Mathf.Abs(angle) < dt)
        {
            CacheTrans.forward = dir;
        }
        else
        {
            // player的前向方向绕up旋转sign方向dt角度
            // sign顺时针为正
            CacheTrans.forward = Quaternion.AngleAxis(dt * sign, Vector3.up) * CacheTrans.forward;
        }
    }

    public static Vector3 Vector3ZeroY(Vector3 v)
    {
        Vector3 v2d = v;
        v2d.y = 0;
        return v2d;
    }

    private void OnDrawGizmos()
    {
        if (!IsLocalPlayer())
        {
            Gizmos.DrawWireSphere(TargetPos, 0.25f);
        }
    }
}
